/**
 * Copyright (C) 2010  Johan Basson
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
package symorg.io;

import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import symorg.util.Node;

/**
 * Org File Management.
 * 
 * @author johan
 */
public class OrgFile {

    private Vector nodes;

    //TODO parse into tree.
    public OrgFile(InputStream in) throws IOException {
        nodes = new Vector();
        Vector items = FileReader.readLines(in);
        Node current = null;
        StringBuffer body = new StringBuffer();
        int counter = -1;


        for (int t = 0; t < items.size(); t++) {
            String line = (String) items.elementAt(t);

           // if (line.trim().length() > 0) {

                if (line.startsWith("#")) {             // Options

                    /* Add body to current node */
                    if (current != null && body.length() > 0) {
                        current.body = body.toString();
                        body.setLength(0);
                        nodes.addElement(current);
                    } else if (current != null) {
                        nodes.addElement(current);
                    }
                    counter++;
                    current = new Node();
                    current.id = counter;


                    Vector subItems = StringTokenizer.tokenize(line, ' ');

                    if (subItems.size() > 0) {
                        String title = (String) subItems.elementAt(0);

                        current.headline = title;

                        if (title.equalsIgnoreCase("#+TAGS") || (title.equalsIgnoreCase("#+TAGS:"))) {
                            current.tags = new String[subItems.size() - 1];
                            for (int e = 1; e < subItems.size(); e++) {
                                current.tags[e - 1] = (String) subItems.elementAt(e);
                            }
                        } else if (title.equalsIgnoreCase("#+SEQ_TODO")) {
                            current.tags = new String[subItems.size() - 1];
                            for (int e = 1; e < subItems.size(); e++) {
                                current.tags[e - 1] = (String) subItems.elementAt(e);
                            }
                        }

                    }

                } else if (line.startsWith("*")) {      // Items

                    /* Add body to current node */

                    if (current != null && body.length() > 0) {
                        current.body = body.toString();
                        body.setLength(0);
                        nodes.addElement(current);
                    } else if (current != null) {
                        nodes.addElement(current);
                    }

                    counter++;
                    current = new Node();
                    current.id = counter;
                    Vector subItems = StringTokenizer.tokenize(line, ' ');

                    if (subItems.size() > 0) {
                        String level = (String) subItems.elementAt(0);
                        current.level = level.length();

                        /* Check for TODO ... */
                        byte start = 1;
                        int last = 0;
                        if (subItems.size() > 1) {
                            String status = (String) subItems.elementAt(1);
                            if (status.equalsIgnoreCase("TODO") || (status.equalsIgnoreCase("DONE"))) {
                                start = 2;
                                current.tag = status;
                            }
                        }

                        /* Build headline */
                        StringBuffer sb = new StringBuffer();
                        for (byte q = start; q < subItems.size(); q++) {
                            String next = (String) subItems.elementAt(q);
                            if (next.startsWith(":")) {
                                last = q;
                                break;
                            } else {
                                if (sb.length() > 0) {
                                    sb.append(" ");
                                }
                                sb.append(next);
                            }
                        }

                        if (last == 0) {
                            last = subItems.size();
                        }

                        /* Create list of tags */
                        current.headline = sb.toString();
                        current.tags = new String[subItems.size() - last];
                        for (int w = last; w < subItems.size(); w++) {
                            current.tags[w - last] = (String) subItems.elementAt(w);
                        }
                    }


                } else {                                // Body

                    body.append(line);
                    body.append("\n\r");
                }
            //}
        }
    }

    public Vector getNodes() {
        return nodes;
    }

    public Vector findLevel1Nodes() {
        Vector out = new Vector();
        for (int t = 0; t < nodes.size(); t++) {
            Node node = (Node) nodes.elementAt(t);
            if (node.level == 1) {
                out.addElement(node);
            }
        }
        return out;
    }

    public Vector findTodo() {
        Vector out = new Vector();
        for (int t = 0; t < nodes.size(); t++) {
            Node node = (Node) nodes.elementAt(t);
            if (node.tag != null && node.tag.equalsIgnoreCase("TODO")) {
                out.addElement(node);
            }
        }
        return out;
    }

    /**
     * Get node by id.
     * 
     * @param nodeId
     * @return
     */
    public Node getNodeById(int nodeId) {
        //TODO can optimize using nodeId
        for (int t = 0; t < nodes.size(); t++) {
            Node node = (Node) nodes.elementAt(t);
            if (node.id == nodeId) {
                return node;
            }
        }
        return null;
    }

    public Vector findChildNodes(int nodeId) {
        int state = 0;
        int nodeLevel = -1;

        Vector out = new Vector();
        for (int t = 0; t < nodes.size(); t++) {
            Node node = (Node) nodes.elementAt(t);
            if (state == 0) {                     // Search for node Id
                if (node.id == nodeId) {
                    nodeLevel = node.level;
                    state = 1;
                }
            } else if (state == 1) {              //
                if (node.level > nodeLevel) {
                    out.addElement(node);
                } else {
                    state = 2;
                }
            } else {
                break;
            }
        }
        return out;
    }

    public boolean isLeaf(int nodeId) {
        return findChildNodes(nodeId).size() == 0;
    }
}
